#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using TileEngineComponent;
using FrameRateComponent;
using Camera_2DComponent;
using MenuComponent;
using MouseComponent;
#endregion

namespace Swarm_Defense
{


    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        public ContentManager content;
        TileEngine tilemap;
        Framerate fps;
        SpriteFont ArialFont;
        SpriteBatch spriteBatch;
        public Camera_2D camera;
        public Menu MainMenu;
        MouseClass Mousey;

        SquareClass Square;
        
        // Enum covering possible game states
        public enum GAMESTATE_ENUM { GAME_MENU, GAME_RUNNING, GAME_PAUSED };

        protected GAMESTATE_ENUM _GameState = GAMESTATE_ENUM.GAME_MENU;
        public GAMESTATE_ENUM GameState
        {
            get { return this._GameState; }
            set { _GameState = value; }
        }

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            content = new ContentManager(Services);
        }


        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            //this.graphics.ToggleFullScreen();
            // for now, this will work for both mark and I.
            // need to figure out how to deal with getting current size, setting new one, etc.
            // should store this in an xml config file, probably.  or something like that. :)
            this.graphics.PreferredBackBufferHeight = 960;
            this.graphics.PreferredBackBufferWidth = 1280;
            this.graphics.ApplyChanges();
            
            SetupTileMap();

            fps = new Framerate(this);
            
            this.fps.Enabled = true;
            this.fps.Visible = true;
            
            camera = new Camera_2D(this);
            

            SetupMenu();
            
            Mousey = new MouseClass(this);
            Mousey.Enabled = true;
            Mousey.Visible = true;


            this.Components.Add(fps);
            this.Components.Add(camera);

            this.Components.Add(Mousey);
            this.Components.Add(MainMenu);
            this.Components.Add(tilemap);


            base.Initialize();
        }

        private void SetupMenu()
        {
            MainMenu = new Menu(this);
            MainMenu.SetupMainMenu(this.graphics.PreferredBackBufferWidth, this.graphics.PreferredBackBufferHeight);

        }
        private void SetupTileMap()
        {
            // Set up the new tilemap
            tilemap = new TileEngine(this);

            tilemap.Left = 0;
            tilemap.Top = 0;
            tilemap.TileWidth = 48;
            tilemap.TileHeight = 48;

            // Need to base these values off of the actual screen size of the 
            // monitor, not what I like.  :)
            tilemap.Width = 20;
            tilemap.Height = 15;

            tilemap.DrawFirstRowTilesOnTransLayers = false;
            tilemap.SetMapPixels(960, 720);
        }
        /// <summary>
        /// Load your graphics content.  If loadAllContent is true, you should
        /// load content from both ResourceManagementMode pools.  Otherwise, just
        /// load ResourceManagementMode.Manual content.
        /// </summary>
        /// <param name="loadAllContent">Which type of content to load.</param>
        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            if (loadAllContent)
            {
                // TODO: Load any ResourceManagementMode.Automatic content
                tilemap.LoadMap(@"content\map000.txt");
                tilemap.AddTileset(@"content\fulltileset_alpha", 48, 48, 0, 0);
                tilemap.AddTileAnimation(108, 7, 4);
                //tilemap.Enabled = true;
                //tilemap.Visible = true;

                spriteBatch = new SpriteBatch(graphics.GraphicsDevice);
                ArialFont = content.Load<SpriteFont>(@"Content\Fonts\Arial48");
            }
            SetUpInterface();
            // TODO: Load any ResourceManagementMode.Manual content
        }


        /// <summary>
        /// Unload your graphics content.  If unloadAllContent is true, you should
        /// unload content from both ResourceManagementMode pools.  Otherwise, just
        /// unload ResourceManagementMode.Manual content.  Manual content will get
        /// Disposed by the GraphicsDevice during a Reset.
        /// </summary>
        /// <param name="unloadAllContent">Which type of content to unload.</param>
        protected override void UnloadGraphicsContent(bool unloadAllContent)
        {
            if (unloadAllContent)
            {
                // TODO: Unload any ResourceManagementMode.Automatic content
                content.Unload();
            }

            // TODO: Unload any ResourceManagementMode.Manual content
        }


        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            tilemap.ScrollByPixels(2, 1);

            // TODO: Add your update logic here
            ProcessKeyboard(); 

            base.Update(gameTime);
        }


        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(new Color(84,58,255));

            switch (this._GameState)
            {
                case GAMESTATE_ENUM.GAME_MENU:
                    DrawMenu();
                    break;
                default:
                    DrawGame();
                    break;
            }

            
            base.Draw(gameTime);
        }

        private void DrawGame()
        {
            tilemap.Enabled = true;
            tilemap.Visible = true;
            MainMenu.Enabled = false;
            MainMenu.Visible = false;
            camera.Enabled = true;
            camera.Visible = true;
        }

        private void DrawMenu()
        {
            tilemap.Enabled = false;
            tilemap.Visible = false;
            MainMenu.Visible= true;
            MainMenu.Enabled = true;
            camera.Enabled = false;
            camera.Visible = false;
        }

        private void ProcessKeyboard()
        {
            KeyboardState keys = Keyboard.GetState();
            if (keys.IsKeyDown(Keys.PageUp))
            {
                if ((tilemap.MapHeight + 1 > tilemap.Width) && (tilemap.MapWidth +1 > tilemap.MapWidth))
                {
                    tilemap.Width += 1;
                    tilemap.Height += 1;
                }

            }
            if (keys.IsKeyDown(Keys.PageDown))
            {
                if ((tilemap.Width - 1 > 0) && (tilemap.Height + 1 > 0))
                {
                    tilemap.Width -= 1;
                    tilemap.Height -= 1;
                }
            }
        }

        /* This sets up the interface for the game.
         * There is a border surrounding the map of the same color as the background.
         * This prevents the boxes that are popping in from being seen, since the tilemap 
         * pops in an entire box at once on the fringe of its map when its time.
         * We make the interface tiles the same color as the background, so it looks "seamless".
         */
        private void SetUpInterface()
        {
            for (int i = 0; i < tilemap.Height-1; i++)
            {
                VerticalInterfaceBorder Border = new VerticalInterfaceBorder("Vertical Interface" + i.ToString(),
                    new Vector2(912, tilemap.TileHeight * i), content.Load<Texture2D> (@"Content\Interface\vertical_background")
                    , 48, 48);
                camera.ActiveObjects.Add(Border);
            }
            for (int i = 0; i < tilemap.Width-1; i++)
            {
                HorizontalInterfaceBorder Border = new HorizontalInterfaceBorder("Horizontal Interface" + i.ToString(),
                    new Vector2(tilemap.TileWidth * i, 672), content.Load < Texture2D > (@"Content\Interface\horizontal_background")
                    , 48, 48);
                camera.ActiveObjects.Add(Border);
            }
            {
                BottomRightInterfaceBorder Border = new BottomRightInterfaceBorder("Btm Right Interface",
                    new Vector2(tilemap.TileWidth * (tilemap.Width-1), tilemap.TileHeight * (tilemap.Height-1)),
                                    content.Load < Texture2D > (@"Content\Interface\bottom_right_background")
                                    , 48, 48);
                camera.ActiveObjects.Add(Border);
            }

            /*Square = new SquareClass(new Vector2(0, 0), content.Load < Texture2D >( @"Content\square"));
            camera.ActiveObjects.Add(Square);*/


            camera.ActiveObjects.Sort();
            spriteBatch.Begin();
            spriteBatch.DrawString(ArialFont, "Hit PageUp and PageDown to zoom.", new Vector2(0.0f, 725.0f), Color.Black);
            spriteBatch.End();

            
        }
    }
}
